package com.ssfeng.youxia.config;

import com.ssfeng.youxia.dao.impl.ShiroSessionDao;
import com.ssfeng.youxia.services.EnvironmentService;
import com.ssfeng.youxia.shiro.KickoutSessionFilter;
import com.ssfeng.youxia.shiro.RetryLimitCredentialsMatcher;
import com.ssfeng.youxia.shiro.ShiroCacheManager;
import com.ssfeng.youxia.shiro.SystemLogoutFilter;
import com.ssfeng.youxia.shiro.realm.SaltAwareRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfiguration {

    @Autowired
    private EnvironmentService environmentService;

    @Autowired
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        /***
         * 登录URL没有登录的用户请求需要登录的页面时自动跳转到登录页面
         */
        factoryBean.setLoginUrl("/tpage/index.html");
        /***
         * 没有权限默认跳转的页面，登录的用户访问了没有被授权的资源自动跳转到的页面
         */
        factoryBean.setUnauthorizedUrl("/error/unauthorized.html");
        /***
         *
         */
        factoryBean.setSuccessUrl("/tpage/loginSuccess.html");
        /***
         * 自定义拦截器
         */
        Map<String, Filter> filters = new HashMap<>();

        /***
         * 退出登录拦截器
         */
        SystemLogoutFilter systemLogoutFilter = systemLogoutFilter();
        filters.put("logout", systemLogoutFilter);

        /***
         * 踢出拦截器
         */
        KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter();
        filters.put("kickoutSessionFilter", kickoutSessionFilter);

        /***
         * 拦截器注册
         */
        factoryBean.setFilters(filters);


        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        /****
         * 静态文件shiro不予拦截
         */
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        filterChainDefinitionMap.put("/image/**", "anon");
        filterChainDefinitionMap.put("/error/kickout.html", "anon");
        /***
         * 登录url
         */
        filterChainDefinitionMap.put("/login/**", "anon");
        /***
         * 退出登录url
         */
        filterChainDefinitionMap.put("/logout", "logout");
        /***
         * 其他请求，权限认证
         */
        filterChainDefinitionMap.put("/**", "user,kickoutSessionFilter");
        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }

    @Autowired
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getSecurityManager(SaltAwareRealm localRealm,
                                                        SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new org.apache.shiro.web.mgt.DefaultWebSecurityManager();
        securityManager.setRealm(localRealm);
        securityManager.setSessionManager(sessionManager);
		securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    public RememberMeManager rememberMeManager() {
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        rememberMeManager.setCookie(rememberMeCookie());
//        rememberMeManager.setCipherKey(org.apache.shiro.codec.Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
        rememberMeManager.setCipherKey(org.apache.shiro.codec.Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
        return rememberMeManager;
    }

    public SimpleCookie rememberMeCookie() {
        SimpleCookie rememberMeCookie = new SimpleCookie();
        rememberMeCookie.setName("rememberMeCookie");
        rememberMeCookie.setHttpOnly(true);
        // 记住一周时间
        rememberMeCookie.setMaxAge(-1);
        return rememberMeCookie;
    }


    @Bean
	@Autowired
    public DefaultWebSessionManager sessionManager(ShiroSessionDao shiroSessionDao) {
        /***
         * session过期时间为半个小时，半个小时用户如果没有操作将自动退出登录
         */
        final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(Long.parseLong(environmentService.getProperty("globalSessionTimeout")));
        sessionManager.setSessionIdCookie(sessionIdCookie());
		sessionManager.setSessionDAO(shiroSessionDao);
        return sessionManager;
    }


    @Autowired
    @Bean(name = "localRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public SaltAwareRealm getLocaleRealm(CredentialsMatcher credentialsMatcher) {
        SaltAwareRealm realm = new SaltAwareRealm();
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }

    @Autowired
    @Bean
    public MethodInvokingFactoryBean getMethodInvokingFactoryBean(
            org.apache.shiro.mgt.SecurityManager securityManager) {
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        factoryBean.setArguments(new Object[]{securityManager});
        return factoryBean;
    }

    @Autowired
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor", "shiroCacheManager"})
    public HashedCredentialsMatcher credentialsMatcher(ShiroCacheManager shiroCacheManager) {
        RetryLimitCredentialsMatcher credentialsMatcher = new RetryLimitCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(environmentService.getProperty("algorithm"));
        credentialsMatcher.setHashIterations(Integer.parseInt(environmentService.getProperty("iterations")));
        credentialsMatcher.setCacheName("halfHour");
        credentialsMatcher.setCacheManager(shiroCacheManager);
        return credentialsMatcher;
    }

    @Bean
    public SimpleCookie sessionIdCookie() {
        SimpleCookie simpleCookie = new SimpleCookie();
        // maxAge=-1 表示浏览器关闭时失效此 Cookie；
        simpleCookie.setMaxAge(-1);
        simpleCookie.setHttpOnly(true);
        simpleCookie.setName("sid");
        return simpleCookie;
    }


    /*
     * <!-- anon 不需要认证 authc 需要认证 user 验证通过或RememberMe登录的都可以 -->
     */

    @Bean
    @Autowired
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Autowired
    @Bean
    public ShiroCacheManager shiroCacheManager(EhCacheCacheManager cacheManager) {
        ShiroCacheManager shiroCacheManager = new ShiroCacheManager();
        shiroCacheManager.setCacheManager(cacheManager);
        return shiroCacheManager;
    }

    public SystemLogoutFilter systemLogoutFilter() {
        return new SystemLogoutFilter();
    }


}
